package com.lx.bilibili.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lx.bean.Result;
import com.lx.bilibili.annotition.LoginValidator;
import com.lx.bilibili.util.JWTUtil;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;

@Component
@Aspect
public class LoginAspect {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 切点，方法上有注解或者类上有注解
     *  拦截类或者是方法上标注注解的方法
     */
    @Pointcut(value = "@annotation(com.lx.bilibili.annotition.LoginValidator) || @within(com.lx.bilibili.annotition.LoginValidator)")
    public void pointCut() {}

    @Around("pointCut()")
    public Object before(ProceedingJoinPoint joinpoint) throws Throwable {
        // 获取方法方法上的LoginValidator注解
        MethodSignature methodSignature = (MethodSignature)joinpoint.getSignature();
        Method method = methodSignature.getMethod();
        LoginValidator loginValidator = method.getAnnotation(LoginValidator.class);
        // 如果有，并且值为false，则不校验
        if (loginValidator != null && !loginValidator.validated()) {
            return joinpoint.proceed(joinpoint.getArgs());
        }
        // 正常校验 获取request和response
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null || requestAttributes.getResponse() == null) {
            // 如果不是从前端过来的，没有request，则直接放行
            return joinpoint.proceed(joinpoint.getArgs());
        }
        HttpServletRequest request = requestAttributes.getRequest();
        HttpServletResponse response = requestAttributes.getResponse();
        // 获取token
        String token = request.getHeader("Authorization");
        if (StringUtils.isBlank(token)) {
            returnNoLogin(response);
            return null;
        }
        System.out.println("=====================进入token校验=====================");
        JWTUtil jwtUtil = new JWTUtil();
        // 校验token
        try {
            Claims claims = jwtUtil.parseJWT(token);

        }catch ( Exception e){
            return null;
        }
        // 放行
        return joinpoint.proceed(joinpoint.getArgs());
    }

    /**
     * 返回未登录的错误信息
     * @param response ServletResponse
     */
    private void returnNoLogin(HttpServletResponse response) throws IOException {
        ServletOutputStream outputStream = response.getOutputStream();
        // 设置返回401 和响应编码
        System.out.println(
                "=====================未登录====================="
        );
        response.setStatus(401);
        response.setContentType("Application/json;charset=utf-8");
        // 构造返回响应体
        Result result = new Result(0, "未登录", null);
        ObjectMapper objectMapper = new ObjectMapper();
        String resultStr = objectMapper.writeValueAsString(result);
        outputStream.write(resultStr.getBytes(StandardCharsets.UTF_8));
    }

}

